﻿using System;

namespace sinetd.Services.Modbus
{
    public class Frame
    {
        public Frame()
        {
            Data = new byte[4];
        }

        public Frame(byte dev, FunctionCodes fc, int a, int b)
        {
            Device = dev;
            FunctionCode = fc;
            Data = new byte[4];
            Data[0] = (byte)(a << 8);
            Data[1] = (byte)(a);
            Data[2] = (byte)(b << 8);
            Data[3] = (byte)(b);
        }

        public byte Device;

        #region ModBus Protocol Data Unit

        public FunctionCodes FunctionCode;
        public byte[] Data;

        #endregion

        public byte CheckSum;

        public int DataInA
        {
            get { return (Data[0] >> 8) + Data[1]; }
        }

        public int DataInB
        {
            get { return (Data[2] >> 8) + Data[3]; }
        }

        //--------------------------------------------------------

        public byte[] Encode()
        {
            byte[] output = new byte[4 + Data.Length];

            output[0] = Device;
            output[1] = (byte)FunctionCode;
            for (int i = 0; i < Data.Length; i++)
                output[2 + i] = Data[i];

            byte[] c = new byte[2 + Data.Length];
            Array.Copy(output, 0, c, 0, 2 + Data.Length);
            Crc16 crc = new Crc16();
            byte[] crc2 = crc.ComputeChecksumBytes(c);
            output[output.Length - 2] = crc2[0];
            output[output.Length - 1] = crc2[1];

            return output;
        }

        public void Decode(byte[] input)
        {
            Device = input[0];
            FunctionCode = (FunctionCodes)input[1];
            Data[0] = input[2];
            Data[1] = input[3];
            Data[2] = input[4];
            Data[3] = input[5];
        }

        public static byte CalculateLrc(byte[] data)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            byte lrc = 0;
            foreach (byte b in data)
                lrc += b;

            lrc = (byte)((lrc ^ 0xFF) + 1);

            return lrc;
        }
    }
}
